#include "StdAfx.h"
#include "CharacterManager.h"
#include <float.h>
#include "CharacterInstance.h"
#include "SkeletonAnim.h"

#include "Command_Buffer.h"
#include "Command_Commands.h"

SPU_NO_INLINE void CSkeletonAnim::Commands_Create(const QuatT& rPhysLocationCurr, const QuatTS& rAnimLocationCurr, Command::CBuffer& buffer)
{
	DEFINE_PROFILER_FUNCTION();

	CCharInstance * __restrict pInstance = m_pInstance;
	CSkeletonPose * __restrict pSkeletonPose = m_pSkeletonPose;

	CAnimationSet* pAnimationSet = &pInstance->m_pModel->m_AnimationSet;

	pSkeletonPose->m_feetLock.Reset();
	m_AccVelocity=Vec3(ZERO);

	buffer.Initialize(pInstance, rPhysLocationCurr, rAnimLocationCurr);

#if !defined(__SPU__)
	extern uint32 g_AnimationUpdates; 	g_AnimationUpdates++;
#endif

	//compute number of animation in this layer
	DynArray<CAnimation> &rCurLayer = m_layers[0].m_transitionQueue.m_animations;
	uint32 numAnimsInLayer = rCurLayer.size();
	uint32 numActiveAnims=0;
	for (uint32 a=0; a<numAnimsInLayer; a++)
	{
		if (rCurLayer[a].m_bActivated==0)
			break;
		numActiveAnims++;	

		/*
		uint32 num = rCurLayer[a].m_Parametric.m_numAnims;
		for (uint32 l=0; l<num; l++)
		{
		int32 nGlobalID = pAnimationSet->GetGlobalIDByAnimID_Fast(rCurLayer[a].m_Parametric.m_nAnimID[l]);
		GlobalAnimationHeaderCAF& rCAF = g_AnimationManager.m_arrGlobalCAF[nGlobalID];
		if (rCAF.IsAssetOnDemand())
		{
		uint32 loaded = rCAF.IsAssetLoaded();
		if (loaded==0)
		{
		int nCurrentFrameID = g_pCharacterManager->m_nUpdateCounter; 
		CryFatalError("CryAnimation: Asset Not Loaded: %s   nCurrentFrameID: %d",rCAF.GetFilePath(),nCurrentFrameID);
		}
		}
		}
		*/
	}

	// base layer
	uint32 objectType =	m_pInstance->m_pModel->m_ObjectType;
	if (numActiveAnims==0 && objectType==CHR)
		return; //without base-animation there is not much we can do 

	if (numActiveAnims)
	{

		f32 pfUserData[NUM_ANIMATION_USER_DATA_SLOTS] = {0.0f};
		m_fAllowMultilayerAnim = 0.0f;	
		f32 fTransWeight=0;
		for (uint32 a=0; a<numActiveAnims; a++)
		{
			SpuStackValue<CAnimation,true,true> stackAnimation(rCurLayer[a]);
			CAnimation &rCurAnimation = stackAnimation;

			f32 fAllowMultilayer = f32( (rCurAnimation.m_AnimParams.m_nFlags & CA_DISABLE_MULTILAYER) ==0 );
			m_fAllowMultilayerAnim += fAllowMultilayer*rCurAnimation.m_fTransitionWeight;

			// store often used pointer/variables in local variables to improve SPU cache simulation
			f32 fTransitionWeight = rCurAnimation.m_fTransitionWeight;			
			f32 * __restrict pSrc = &rCurAnimation.m_AnimParams.m_fUserData[0];

			for (int i=0; i<NUM_ANIMATION_USER_DATA_SLOTS; i++)
				pfUserData[i] += pSrc[i]*fTransitionWeight;

			fTransWeight   += rCurAnimation.m_fTransitionWeight;
		}

		memcpy(&m_fUserData[0], pfUserData , NUM_ANIMATION_USER_DATA_SLOTS * sizeof(f32));

		if (pSkeletonPose->m_bFullSkeletonUpdate==0)
			return;

		Command::ClearFull* clearbuffer = buffer.CreateCommand<Command::ClearFull>();
		clearbuffer->m_TargetBuffer		= Command::TargetBuffer;


		for (uint32 i=0; i<numActiveAnims; i++)
		{
			SpuStackValue<CAnimation, false,true> spuAnim( rCurLayer[i] );	
			Commands_BasePlayback(spuAnim,buffer);
		}

		Command::NormalizeFull* norm = buffer.CreateCommand<Command::NormalizeFull>();
		norm->m_TargetBuffer = Command::TargetBuffer;

	/*	if (rAnimLocationCurr.s != 1.0f)
		{
			Command::ScaleUniformFull* uscale = buffer.CreateCommand<Command::ScaleUniformFull>();
			uscale->m_TargetBuffer = Command::TargetBuffer;
			uscale->m_fScale = rAnimLocationCurr.s;
		}*/

		// Store feet position
		uint32 t0 = uint32(Console::GetInst().ca_LockFeetWithIK);
		uint32 t1 = m_IsAnimPlaying&1;
		if (t0 && t1)
		{		
			Command::PoseModifier* ac = buffer.CreateCommand<Command::PoseModifier>();
			ac->m_TargetBuffer = Command::TargetBuffer;
			ac->m_pPoseModifier = pSkeletonPose->m_feetLock.Store();
		}
	}

	// Upper layers
	uint16 mask = 0xffff; 
	uint32 numJoints = m_arrJointMask.size();
	for (uint32 i=0; i<numJoints; i++)
		mask &= m_arrJointMask[i];

	for (uint32 i=1; i<numVIRTUALLAYERS; i++)
	{
		//If an animations is active (i.e. reload) it will overwrite the pose-modifier in the same layer
		DynArray<CAnimation> &layer = m_layers[i].m_transitionQueue.m_animations;
		uint32 animCount = layer.size();
		for (uint32 j=0; j<animCount; ++j)
		{
			if (layer[j].m_bActivated == 0)
				break;

			SpuStackValue<CAnimation, false, true> spuAnim(layer[j]);
			const CAnimation &anim = spuAnim;
			const ModelAnimationHeader* pAnim = SPU_MAIN_PTR(pAnimationSet->GetModelAnimationHeader(anim.m_nAnimID));
			if (pAnim->m_nAssetType == AIM_File)
				continue;
			Commands_LPlayback(anim, Command::TargetBuffer, i, mask, buffer);
		}

		if (numActiveAnims)
		{
			if (IAnimationPoseModifier* pPoseModifier = m_layers[i].m_poseModifier.get())
			{
				SAnimationPoseModiferParams poseModifierParams;
				poseModifierParams.pCharacterInstance = pInstance;

				float fInstanceDeltaTime = pInstance->m_fDeltaTime;
				if (fInstanceDeltaTime != 0.0f)
					poseModifierParams.timeDelta = fInstanceDeltaTime;
				else
					poseModifierParams.timeDelta = pInstance->m_fOriginalDeltaTime;

				poseModifierParams.locationNextPhysics = rPhysLocationCurr;
				poseModifierParams.locationNextAnimation = rAnimLocationCurr;
				Skeleton::CPoseData* pPoseData = pSkeletonPose->GetPoseDataWriteable();
				poseModifierParams.pPoseRelative = &pPoseData->m_pJointsRelative[0]; // TEMP: Should be NULL.
				poseModifierParams.pPoseAbsolute = &pPoseData->m_pJointsAbsolute[0]; // TEMP: Should be NULL.
				poseModifierParams.jointCount = 0;

				//Aim-IK,Look-IK and all other modifiers should be in layers
				IAnimationPoseBlenderDir *pIPoseBlenderAim = pSkeletonPose->GetIPoseBlenderAim();
				if (pIPoseBlenderAim)
				{
					CPoseBlenderAim& rPoseBlenderAim = *static_cast<CPoseBlenderAim*>(pIPoseBlenderAim);
					if (i == rPoseBlenderAim.m_blender.m_nDirLayer)
					{
						bool status = rPoseBlenderAim.Update(poseModifierParams);
						if (status)
						{
							Command::PoseModifier* pCommand = buffer.CreateCommand<Command::PoseModifier>();
							pCommand->m_TargetBuffer = Command::TargetBuffer;
							pCommand->m_pPoseModifier = pPoseModifier;
						}
						continue;
					} 
				}

				IAnimationPoseBlenderDir *pIPoseBlenderLook = pSkeletonPose->GetIPoseBlenderLook();
				if (pIPoseBlenderLook)
				{
					CPoseBlenderLook& rPoseBlenderLook = *static_cast<CPoseBlenderLook*>(pIPoseBlenderLook);
					if (i == rPoseBlenderLook.m_blender.m_nDirLayer)
					{
						bool status = rPoseBlenderLook.Update(poseModifierParams);
						if (status)
						{
							Command::PoseModifier* pCommand = buffer.CreateCommand<Command::PoseModifier>();
							pCommand->m_TargetBuffer = Command::TargetBuffer;
							pCommand->m_pPoseModifier = pPoseModifier;
						}
						continue;
					}
				}

				//its another pose-modifier, probably the STAP system
				Command::PoseModifier* pCommand = buffer.CreateCommand<Command::PoseModifier>();
				pCommand->m_TargetBuffer = Command::TargetBuffer;
				pCommand->m_pPoseModifier = pPoseModifier;
			}
		}
	}

	if (numActiveAnims)
	{
		// Restore feet position
		uint32 x0 = uint32(Console::GetInst().ca_LockFeetWithIK);
		uint32 x1 = m_IsAnimPlaying;
		if (x0 && x1)
		{
			Command::PoseModifier* ac = buffer.CreateCommand<Command::PoseModifier>();
			ac->m_TargetBuffer = Command::TargetBuffer;
			ac->m_pPoseModifier = pSkeletonPose->m_feetLock.Restore();
		}
	}
}

////////////////////////////////////////////////////////////////////////////
//                    playback of one single animation                    //
////////////////////////////////////////////////////////////////////////////
SPU_NO_INLINE void CSkeletonAnim::Commands_BasePlayback(const CAnimation& rAnim, Command::CBuffer& buffer)
{	
	if (rAnim.m_Parametric == NULL)
	{
		//regular asset
		CAnimationSet* pAnimationSet = &m_pInstance->m_pModel->m_AnimationSet;
		uint32 nAnimID=rAnim.m_nAnimID;
		uint32 nSampleRateHZ30 = rAnim.m_AnimParams.m_nFlags&CA_KEYFRAME_SAMPLE_30Hz;

		const ModelAnimationHeader* pMAG = pAnimationSet->GetModelAnimationHeader(rAnim.m_nAnimID);
		assert(pMAG);
		int32 nEGlobalID = pMAG->m_nGlobalAnimId;
		if (pMAG->m_nAssetType==CAF_File)
		{
			// use a stack object on SPU here to reduce simulation time
			SpuStackValue<GlobalAnimationHeaderCAF, true, true> stackAnimHeader( g_AnimationManager.m_arrGlobalCAF[nEGlobalID] );
			GlobalAnimationHeaderCAF& rCAF = stackAnimHeader; 

			Command::SampleAddAnimFull* ac = buffer.CreateCommand<Command::SampleAddAnimFull>();
			ac->m_nEAnimID					=	rAnim.m_nAnimID;
			ac->m_flags             = 0;
			ac->m_flags			       |=	m_AnimationDrivenMotion ? Command::SampleAddAnimFull::Flag_ADMotion : 0;
			ac->m_fWeight						=	rAnim.m_fTransitionWeight;

			f32 time_new0	=	rAnim.m_fAnimTime; 
			int32 segtotal	= rCAF.m_Segments - 1;
			int32 segcount 	= rAnim.m_nSegmentCounter;
			f32 segdur 			= rCAF.GetSegmentDuration(segcount);
			f32 totdur 			= rCAF.m_fTotalDuration ? rCAF.m_fTotalDuration : 1.0f;
			f32 segbase 		= rCAF.m_SegmentsTime[segcount];
			f32 percent 		= segdur/totdur;
			f32 time_new	=	time_new0*percent+segbase;	
			ac->m_fETimeNew					=	time_new;			//this is a percentage value between 0-1
			if (nSampleRateHZ30)
			{
				f32 fKeys			=	totdur*TICKS_PER_SECOND;
				f32 fKeyTime	=	time_new*fKeys;
				ac->m_fETimeNew				=	f32(uint32(fKeyTime+0.45f))/fKeys;
			 //	float fColor2[4] = {1,0,0,1};
			 //	g_pIRenderer->Draw2dLabel( 1,g_YLine, 2.3f, fColor2, false,"fKeys: %f  fKeyTime: %f   m_fETimeNew: %f",fKeys,fKeyTime,ac->m_fETimeNew);
			 //	g_YLine+=23;
			}
		}

		if (pMAG->m_nAssetType==AIM_File)
		{
			// use a stack object on SPU here to reduce simulation time
			SpuStackValue<GlobalAnimationHeaderAIM, true, true> stackAnimHeader( g_AnimationManager.m_arrGlobalAIM[nEGlobalID] );
			GlobalAnimationHeaderAIM& rAIM = stackAnimHeader; 
			assert(rAnim.m_fAnimTime>=0.0f && rAnim.m_fAnimTime<=1.0f);
			Command::SampleAddPoseFull* ac = buffer.CreateCommand<Command::SampleAddPoseFull>();
			ac->m_nEAnimID					=	rAnim.m_nAnimID;
			ac->m_flags             = 0;
			ac->m_fWeight						=	rAnim.m_fTransitionWeight;
			ac->m_fETimeNew					=	rAnim.m_fAnimTime; //this is a percentage value between 0-1
			if (1)
			{
				f32 fDuration		= max(SECONDS_PER_TICK,rAIM.m_fTotalDuration);
				f32 fKeys				=	fDuration*TICKS_PER_SECOND;
				f32 fKeyTime		=	ac->m_fETimeNew*fKeys;
				ac->m_fETimeNew	=	f32(uint32(fKeyTime+0.45f))/fKeys;
				//float fColor2[4] = {1,0,0,1};
				//g_pIRenderer->Draw2dLabel( 1,g_YLine, 2.3f, fColor2, false,"fKeys: %f  fKeyTime: %f   m_fETimeNew: %f",fKeys,fKeyTime,ac->m_fETimeNew);
				//g_YLine+=23;
			}
		}

	}
	else 
	{
		Commands_BaseEvaluationLMG(rAnim, Command::TargetBuffer, buffer);
	}
	m_IsAnimPlaying = 1;

}

///////////////////////////////////////////////////////////////////////////////////////////
//                       evaluation of a locomotion group                                //
///////////////////////////////////////////////////////////////////////////////////////////
SPU_NO_INLINE void CSkeletonAnim::Commands_BaseEvaluationLMG( const CAnimation& rAnim, uint32 nTargetBufferaa, Command::CBuffer& buffer)
{	
	CRY_ASSERT(rAnim.m_Parametric);

	const SParametric &rCurLocoGroup = *rAnim.m_Parametric;
	assert(rCurLocoGroup.m_nParametricID>=0);
	CAnimationSet* pAnimationSet = &m_pInstance->m_pModel->m_AnimationSet;
	uint32 numAnims = pAnimationSet->GetAnimationCount();
	uint32 nAnimID	=	rCurLocoGroup.m_nParametricID;

	const ModelAnimationHeader* pAnim = pAnimationSet->GetModelAnimationHeader(rCurLocoGroup.m_nParametricID);
	if (pAnim==0)
		return;
	assert(pAnim->m_nAssetType == LMG_File);

	GlobalAnimationHeaderLMG& rGlobalAnimHeaderLMG = g_AnimationManager.m_arrGlobalLMG[pAnim->m_nGlobalAnimId];
	uint32 numSpliceAnims = rGlobalAnimHeaderLMG.m_strSpliceAnim.size();
	uint32 nTargetBuffer  = (numSpliceAnims) ? Command::TmpBuffer : Command::TargetBuffer;

	f32 fTransitionWeight=1.0f;
	if (nTargetBuffer==Command::TargetBuffer)
		fTransitionWeight=rAnim.m_fTransitionWeight;

	//-----------------------------------------------------------------------------------
	//-----              average all animations in a blend-space                   ------
	//-----------------------------------------------------------------------------------
	int8 idf[MAX_LMG_ANIMS];	memset( &idf,1,MAX_LMG_ANIMS*sizeof(int8));
	int32 ids[MAX_LMG_ANIMS];

#if !defined(__SPU__)
	f32 fTotalSum=0;
	for (int32 i=0; i<rCurLocoGroup.m_numAnims; i++)
		fTotalSum += rCurLocoGroup.m_fBlendWeight[i];
	if ( fabsf(fTotalSum-1.0f)>0.09f )
		AnimFileWarning(m_pInstance->m_pModel->GetModelFilePath(),"CryAnimation: LMG weights don't sum up to 1. fTotalSum: %f",fTotalSum);
#endif

	uint32 f=0;
	for (int32 i=0; i<rCurLocoGroup.m_numAnims; i++)
	{
		f32 weight			= rCurLocoGroup.m_fBlendWeight[i];
		uint32 nID			= rCurLocoGroup.m_nAnimID[i];
		int32 nGlobalID	=	pAnimationSet->GetGlobalIDByAnimID_Fast(rCurLocoGroup.m_nAnimID[i]);

		GlobalAnimationHeaderCAF& rGlobalAnimHeaderAssets = g_AnimationManager.m_arrGlobalCAF[nGlobalID];
		rGlobalAnimHeaderAssets.m_nTouchedCounter=rGlobalAnimHeaderLMG.m_nTouchedCounter;
		if (weight && idf[i])
		{
			idf[i]=0;
			ids[f]=i;
			f++;
			int32 id0=rCurLocoGroup.m_nAnimID[i];
			for (int32 q=i+1; q<rCurLocoGroup.m_numAnims; q++)
			{
				int32 id1=rCurLocoGroup.m_nAnimID[q];
				if (id0==id1 && rCurLocoGroup.m_fBlendWeight[q])
				{
					idf[q]=0;
					ids[f]=q;
					f++;
				}
			}
		}
	}

#if !defined(__SPU__)
	if (f==0)
		AnimFileWarning(m_pInstance->m_pModel->GetModelFilePath(),"CryAnimation: LMG asset sorting problem: f=%d",f);
	assert (f);
#endif


	int  arrAnimIndices[MAX_LMG_ANIMS];
	f32  arrAnimWeights[MAX_LMG_ANIMS];
	Vec3 arrAnimVelocities[MAX_LMG_ANIMS];
	int arrExampleID[MAX_LMG_ANIMS];

	int32 oldid =	-1; //rCurLocoGroup.m_nAnimID[i];
	uint32 c=0;
	for (uint32 s=0; s<f; s++)
	{
		int i	=	ids[s];
		f32 weight		= rCurLocoGroup.m_fBlendWeight[i];
		int newid			= rCurLocoGroup.m_nAnimID[i];
		Vec3 Velocity	= rGlobalAnimHeaderLMG.m_arrBSAnimations[i].m_qVelocity;
		//float fColor1[4] = {1,0,0,1};
		//g_pIRenderer->Draw2dLabel( 1,g_YLine, 1.3f, fColor1, false,"example %d used weight:%f",newid, weight);
		//g_YLine+=10;

		if (newid != oldid)
		{
			arrAnimIndices[c]=newid;
			arrAnimWeights[c]=weight;
			arrAnimVelocities[c]=Velocity;
			arrExampleID[c]=i;
			c++;
			oldid=newid;
			continue;
		}
		if (c > 0) arrAnimWeights[c-1]+=weight;
	}


	if (nTargetBuffer==Command::TmpBuffer)
	{
		Command::ClearFull* clearbuffer = buffer.CreateCommand<Command::ClearFull>();
		clearbuffer->m_TargetBuffer		= Command::TmpBuffer;
	}

	if (pAnim->m_nAssetType == LMG_File)
	{
		if (rGlobalAnimHeaderLMG.m_jointList.empty()==0)
		{
			Command::JointMask* pCommand = buffer.CreateCommand<Command::JointMask>();
			pCommand->m_pMask =  &rGlobalAnimHeaderLMG.m_jointList[0];
			pCommand->m_count = rGlobalAnimHeaderLMG.m_jointList.size();
		}
	} 

	//-------------------------------------------------------------------------------------
	//----------            evaluate and blend root-joint       ---------------------------
	//-------------------------------------------------------------------------------------
	f32 fBlendWeights  =	0; //rCurLocoGroup.m_fBlendWeight[i];
	for (uint32 s=0; s<c; s++)
	{
		int example = arrExampleID[s];
		f32 weight = arrAnimWeights[s];

		//	int id		 = arrAnimIndices[s];
		//	float fColor2[4] = {0,1,0,1};
		//	g_pIRenderer->Draw2dLabel( 1,g_YLine, 1.3f, fColor2, false,"example %d used weight:%f",id, weight);
		//	g_YLine+=10;

		const ModelAnimationHeader* pMAG = pAnimationSet->GetModelAnimationHeader(rAnim.m_Parametric->m_nAnimID[example]);
		assert(pMAG);
		int32 nEGlobalID = pMAG->m_nGlobalAnimId;
		assert(pMAG->m_nAssetType==CAF_File);
		SpuStackValue<GlobalAnimationHeaderCAF, true, true> stackAnimHeader( g_AnimationManager.m_arrGlobalCAF[nEGlobalID] );
		GlobalAnimationHeaderCAF& rCAF = stackAnimHeader; 

		Command::SampleAddAnimFull* fetch = buffer.CreateCommand<Command::SampleAddAnimFull>();
		fetch->m_nEAnimID			=	rAnim.m_Parametric->m_nAnimID[example];
		fetch->m_fWeight      = weight*fTransitionWeight;
		fetch->m_flags=0;
		fetch->m_flags		   |=	m_AnimationDrivenMotion ? Command::SampleAddAnimFull::Flag_ADMotion : 0;
		fetch->m_flags		   |=	(nTargetBuffer==Command::TmpBuffer) ? Command::SampleAddAnimFull::Flag_TmpBuffer : 0;

		f32 time_new0	=	rAnim.m_fAnimTime; 
		int32 segtotal	= rCAF.m_Segments - 1;
		int32 segcount 	= rAnim.m_Parametric->m_nSegmentCounter[example];
		f32 segdur 			= rCAF.GetSegmentDuration(segcount);
		f32 totdur 			= rCAF.m_fTotalDuration ? rCAF.m_fTotalDuration : 1.0f;
		f32 segbase 		= rCAF.m_SegmentsTime[segcount];
		f32 percent 		= segdur/totdur;
		fetch->m_fETimeNew	=	time_new0*percent+segbase;//this is a percentage value between 0-1	

		fBlendWeights+=weight;
		m_AccVelocity += weight*rAnim.m_fTransitionWeight*arrAnimVelocities[s];
	}

	if (pAnim->m_nAssetType == LMG_File)
	{
		if (!rGlobalAnimHeaderLMG.m_jointList.empty())
		{
			Command::JointMask* pCommand = buffer.CreateCommand<Command::JointMask>();
			pCommand->m_pMask =  NULL;
			pCommand->m_count = 0;
		}
	}
	m_IsAnimPlaying |= 1;

#if !defined(__SPU__)
	assert( fabsf(fBlendWeights-1.0f)<0.05f );
#endif // !__SPU__

	/*
	Vec3 Velocity = Matrix33::CreateRotationZ(result.m_fCurrentStreife) * Vec3(0,result.m_fCurrentSpeed,0);
	Vec3 m_vCurrentVelocity	=	Velocity;
	f32  m_fRelRotation			= result.m_fCurrentTurn*m_pInstance->m_fDeltaTime;
	f32  m_fRelRotation2		= result.m_fRelRotation;
	Vec3 m_vRelTranslation	=	-Velocity*m_pInstance->m_fDeltaTime;
	g_pIRenderer->Draw2dLabel( 1,g_YLine, 1.3f, fColor2, false,"Velocity: %f %f %f   speed: %f  turn: %f   travel: %f",Velocity.x,Velocity.y,Velocity.z,result.m_fCurrentSpeed,result.m_fCurrentTurn,result.m_fCurrentStreife);
	g_YLine+=10;
	*/

	//-----------------------------------------------------------------------------------------------------
	if (nTargetBuffer==Command::TmpBuffer)
	{
		Command::NormalizeFull* norm = buffer.CreateCommand<Command::NormalizeFull>();
		norm->m_TargetBuffer		= nTargetBuffer;

		for (uint32 i=0; i<numSpliceAnims; i++)
		{
			const SCRCName &strSpliceAnim = rGlobalAnimHeaderLMG.m_strSpliceAnim[i];
			int32 nAnimIDNS	= pAnimationSet->GetAnimIDByCRC(strSpliceAnim.m_CRC32);
			if (nAnimIDNS>=0)
			{ 
				const ModelAnimationHeader* pAnimHeaderNS = pAnimationSet->GetModelAnimationHeader(nAnimIDNS);
				assert(pAnimHeaderNS->m_nAssetType==CAF_File);
				if (pAnimHeaderNS->m_nAssetType==CAF_File)
				{
					GlobalAnimationHeaderCAF& rCAF = g_AnimationManager.m_arrGlobalCAF[pAnimHeaderNS->m_nGlobalAnimId];
					rCAF.m_nTouchedCounter=rGlobalAnimHeaderLMG.m_nTouchedCounter;

					Command::SampleAnimPart* ac = buffer.CreateCommand<Command::SampleAnimPart>();
					ac->m_TargetBuffer				= nTargetBuffer;
					ac->m_nMask								= 0;
					ac->m_nFeatherBlend				= 0;
					ac->m_nEAnimID						=	nAnimIDNS;
					ac->m_fAnimTime						=	rAnim.m_fAnimTime;			//this is a percentage value between 0-1
					ac->m_fWeight 						= 1.0f;
				}
			}
		}

		Command::CopyAddAnimFull* copy_add = buffer.CreateCommand<Command::CopyAddAnimFull>();
		copy_add->m_SourceBuffer		= Command::TmpBuffer; 
		copy_add->m_TargetBuffer		= Command::TargetBuffer;
		copy_add->m_fWeight					= rAnim.m_fTransitionWeight;
	}
}

////////////////////////////////////////////////////////////////////////////
//                    playback of one single animation                    //
////////////////////////////////////////////////////////////////////////////
SPU_NO_INLINE void CSkeletonAnim::Commands_LPlayback(const CAnimation& rAnim, uint32 nTargetBuffer, uint32 nVLayer, uint32 mask, Command::CBuffer& buffer)
{
	CAnimationSet* pAnimationSet = &m_pInstance->m_pModel->m_AnimationSet;
	uint32 nSampleRateHZ30 = rAnim.m_AnimParams.m_nFlags&CA_KEYFRAME_SAMPLE_30Hz;

	if (rAnim.m_Parametric == NULL)
	{
		int32 nAnimID = rAnim.m_nAnimID;
		const ModelAnimationHeader* pAnim = pAnimationSet->GetModelAnimationHeader(nAnimID);
		if (pAnim->m_nAssetType==CAF_File)
		{
			if (mask==0xffff)
			{
				Command::SampleAnimPart* ac = buffer.CreateCommand<Command::SampleAnimPart>();
				ac->m_TargetBuffer				= nTargetBuffer;
				ac->m_nMask								= 255;
				ac->m_nFeatherBlend				= 0;
				ac->m_nEAnimID						=	rAnim.m_nAnimID;
				ac->m_fAnimTime						=	rAnim.m_fAnimTime;					//this is a percentage value between 0-1
				if (nSampleRateHZ30)
				{
					SpuStackValue<GlobalAnimationHeaderCAF, true, true> stackAnimHeader(  g_AnimationManager.m_arrGlobalCAF[pAnim->m_nGlobalAnimId] );
					GlobalAnimationHeaderCAF& rCAF = stackAnimHeader; 
					f32 fDuration		= max(SECONDS_PER_TICK,rCAF.m_fTotalDuration);
					f32 fKeys			=	fDuration*TICKS_PER_SECOND;
					f32 fKeyTime	=	ac->m_fAnimTime*fKeys;
					ac->m_fAnimTime 	=	f32(uint32(fKeyTime+0.45f))/fKeys;
					//	float fColor2[4] = {1,0,0,1};
					//	g_pIRenderer->Draw2dLabel( 1,g_YLine, 2.3f, fColor2, false,"fKeys: %f  fKeyTime: %f   m_fETimeNew: %f",fKeys,fKeyTime,ac->m_fAnimTime);
					//	g_YLine+=23;
				}
				f32 w0 = rAnim.m_fTransitionWeight;											//this is a percentage value between 0-1
				f32 w1 = m_layers[nVLayer].m_transitionQueue.m_additiveWeights;
				f32 w2 = m_fAllowMultilayerAnim;
				f32 w3 = m_layers[nVLayer].m_transitionQueue.m_blending;
				f32 w4 = m_layers[nVLayer].m_transitionQueue.m_blendingMultiplier;
				ac->m_fWeight							=	w0*w1*w2*w3*w4;								//this is a percentage value between 0-1
			} 
			else 
			{
				Command::SampleFeatherAnimPart* ac = buffer.CreateCommand<Command::SampleFeatherAnimPart>();
				ac->m_TargetBuffer				= nTargetBuffer;
				ac->m_nMask								= 255;
				ac->m_nFeatherBlend				= 1;
				ac->m_nEAnimID						=	rAnim.m_nAnimID;
				ac->m_fAnimTime						=	rAnim.m_fAnimTime;			//this is a percentage value between 0-1
				if (nSampleRateHZ30)
				{
					SpuStackValue<GlobalAnimationHeaderCAF, true, true> stackAnimHeader(  g_AnimationManager.m_arrGlobalCAF[pAnim->m_nGlobalAnimId] );
					GlobalAnimationHeaderCAF& rCAF = stackAnimHeader; 
					f32 fDuration		= max(SECONDS_PER_TICK,rCAF.m_fTotalDuration);
					f32 fKeys			=	fDuration*TICKS_PER_SECOND;
					f32 fKeyTime	=	ac->m_fAnimTime*fKeys;
					ac->m_fAnimTime 	=	f32(uint32(fKeyTime+0.45f))/fKeys;
				//	float fColor2[4] = {1,0,0,1};
				//	g_pIRenderer->Draw2dLabel( 1,g_YLine, 2.3f, fColor2, false,"fKeys: %f  fKeyTime: %f   m_fETimeNew: %f",fKeys,fKeyTime,ac->m_fAnimTime);
				//	g_YLine+=23;
				}

				f32 w0 = rAnim.m_fTransitionWeight;			
				f32 w1 = m_layers[nVLayer].m_transitionQueue.m_additiveWeights;
				f32 w2 = m_fAllowMultilayerAnim;
				f32 w3 = m_layers[nVLayer].m_transitionQueue.m_blending;
				f32 w4 = m_layers[nVLayer].m_transitionQueue.m_blendingMultiplier;
				ac->m_fWeight							=	w0*w1*w2*w3*w4;			//this is a percentage value between 0-1

				uint32 numJoints = m_arrJointMask.size();
				for (uint32 i=0; i<numJoints; i++)
					ac->m_arrFeatherMask[i] = ((m_arrJointMask[i]>>nVLayer)&1)<<7; //temporary	
			}
		}

		if (pAnim->m_nAssetType==AIM_File)
		{
			Command::SamplePosePart* ac = buffer.CreateCommand<Command::SamplePosePart>();
			ac->m_TargetBuffer				= nTargetBuffer;
			ac->m_nEAnimID						=	rAnim.m_nAnimID;
			ac->m_fAnimTime						=	rAnim.m_fAnimTime;					//this is a percentage value between 0-1
			f32 w0 = rAnim.m_fTransitionWeight;											//this is a percentage value between 0-1
			f32 w1 = m_layers[nVLayer].m_transitionQueue.m_additiveWeights;
			f32 w2 = m_fAllowMultilayerAnim;
			f32 w3 = m_layers[nVLayer].m_transitionQueue.m_blending;
			f32 w4 = m_layers[nVLayer].m_transitionQueue.m_blendingMultiplier;
			ac->m_fWeight							=	w0*w1*w2*w3*w4;								//this is a percentage value between 0-1
		}
		m_IsAnimPlaying |= 0xfffe;
	}

}

//---------------------------------------------------------------------------------------------------------
//-----      IvoH: not a good idea to modify values in SkeletonPose directly                 --------------
//-----            this should go through the command-buffer                                 --------------
//---------------------------------------------------------------------------------------------------------
SPU_NO_INLINE void CSkeletonAnim::Commands_CreateAimPoseQueue(SDirectionalBlender& _rDirIK, uint32 useDirPosesInBaseAnim)
{

	CAnimationSet* pAnimationSet = &m_pInstance->m_pModel->m_AnimationSet;
	CSkeletonPose* pSkeletonPose = &m_pInstance->m_SkeletonPose;

	SpuStackValue<SDirectionalBlender, true, true> stackDirIK(_rDirIK);
	SDirectionalBlender& rDirIK = stackDirIK;

	uint32 nDirIKLayer	=	rDirIK.m_nDirLayer;
	f32 fDirIKLayerWeight = 0;
	if (nDirIKLayer<numVIRTUALLAYERS)
		fDirIKLayerWeight = m_layers[nDirIKLayer].m_transitionQueue.m_blending;

	f32 t0=1.0f-fDirIKLayerWeight;
	f32 t1=fDirIKLayerWeight;

	//	float fTextColor[4] = {1,0,0,1};
	//	g_pIRenderer->Draw2dLabel( 1,g_YLine, 1.4f, fTextColor, false,"Commands_CreateAimPoseQueue: %d  fDirIKLayerWeight: %f: numAnimsInLayer0: %d",nDirIKLayer,fDirIKLayerWeight,numAnimsInLayer0 );	
	//	g_YLine+=16.0f;

	rDirIK.m_numActiveDirPoses=0;
	rDirIK.m_nLastValidDirPose=-1;
	for (uint32 i=0; i<MAX_EXEC_QUEUE*2; i++)
	{
		rDirIK.m_DirInfo[i].m_fWeight				= 0; 
		rDirIK.m_DirInfo[i].m_numDirPoses		= 0; 
		rDirIK.m_DirInfo[i].m_nGlobalDirID0	= -1; 
		rDirIK.m_DirInfo[i].m_nGlobalDirID1	= -1;
		rDirIK.m_DirInfo[i].m_fAnimTime			= 0.0f;
	}


	//-----------------------------------------------------------------------------------
	//-----    take all Dir-Poses attached to the animation name in the CAL-file    -----
	//-----------------------------------------------------------------------------------
	rDirIK.m_numActiveDirPoses = 0;
	if (useDirPosesInBaseAnim)
	{
		uint32 numActiveAnimsL0=0;
		DynArray<CAnimation> &rCurLayer0 = m_layers[0].m_transitionQueue.m_animations;
		uint32 numAnimsInLayer0 = rCurLayer0.size();
		for (uint32 a=0; a<numAnimsInLayer0; a++)
		{
			if (rCurLayer0[a].m_bActivated==0)
				break;
			numActiveAnimsL0++;	
		}

		for (uint32 i=0; i<numActiveAnimsL0; i++)
		{
			CAnimation 	&rCurAnimation = m_layers[0].m_transitionQueue.m_animations[i];
			assert(rCurAnimation.m_bActivated);

			//check the first aim-id
			if (rCurAnimation.m_nAnimDirID0<0)
				continue;
			const ModelAnimationHeader* pAnimHeader = SPU_MAIN_PTR( pAnimationSet->GetModelAnimationHeader(rCurAnimation.m_nAnimDirID0) );
			if (pAnimHeader==0)
				continue;
			if (pAnimHeader->m_nAssetType!=AIM_File)
				continue;
			assert(pAnimHeader->m_nGlobalAnimId>-1);
			GlobalAnimationHeaderAIM& rAIM0 = g_AnimationManager.m_arrGlobalAIM[pAnimHeader->m_nGlobalAnimId];
			uint32 numPoses = rAIM0.m_arrAimIKPosesAIM.size();
			if (numPoses==0)
				continue;
			if (rAIM0.m_nExist==0)
				continue;

			SDirInfo		&rCurDirInfo = rDirIK.m_DirInfo[rDirIK.m_numActiveDirPoses];
			rCurDirInfo.m_numDirPoses	= 0;
			rCurDirInfo.m_fWeight		= rCurAnimation.m_fTransitionWeight*t0;
			rCurDirInfo.m_fAnimTime	= rCurAnimation.m_fAnimTime;
			rCurDirInfo.m_nGlobalDirID0	= pAnimHeader->m_nGlobalAnimId; 
			rCurDirInfo.m_numDirPoses++;	

			rDirIK.m_numActiveDirPoses++;

			//check the second dir-id
			if (rCurAnimation.m_nAnimDirID1<0)
				continue;
			pAnimHeader = SPU_MAIN_PTR( pAnimationSet->GetModelAnimationHeader(rCurAnimation.m_nAnimDirID1) );
			if (pAnimHeader==0)
				continue;
			if (pAnimHeader->m_nAssetType!=AIM_File)
				continue;
			assert(pAnimHeader->m_nGlobalAnimId>-1);
			GlobalAnimationHeaderAIM& rGAH1 = g_AnimationManager.m_arrGlobalAIM[pAnimHeader->m_nGlobalAnimId];
			numPoses = rGAH1.m_arrAimIKPosesAIM.size();
			if (numPoses==0)
				continue;
			if (rGAH1.m_nExist==0)
				continue;
			rCurDirInfo.m_nGlobalDirID1	= pAnimHeader->m_nGlobalAnimId; 
			rCurDirInfo.m_numDirPoses++;
		}
	}

	//-----------------------------------------------------------------------------------
	//-----    check if there are dir-poses in the same layer like the DIR-IK       -----
	//-----------------------------------------------------------------------------------
	if (nDirIKLayer<1 || nDirIKLayer>=numVIRTUALLAYERS)
		return;

	const DynArray<CAnimation>& rCurLayer = m_layers[nDirIKLayer].m_transitionQueue.m_animations;
	uint32 numAnimsInLayer = rCurLayer.size();
	uint32 numActiveAnims=0;
	for (uint32 a=0; a<numAnimsInLayer; a++)
	{
		if (rCurLayer[a].m_bActivated==0)
			break;
		numActiveAnims++;
	}

	//g_pIRenderer->Draw2dLabel( 1,g_YLine, 1.4f, fTextColor, false,"fDirIKLayerWeight: %f    numActiveAnims: %d",fDirIKLayerWeight,numActiveAnims);	
	//g_YLine+=16.0f;
	for (uint32 i=0; i<numActiveAnims; i++)
	{
		int32 nAnimID = rCurLayer[i].m_nAnimID;
		assert(rCurLayer[i].m_bActivated);
		const ModelAnimationHeader* pAnim = SPU_MAIN_PTR( pAnimationSet->GetModelAnimationHeader(nAnimID) );
		assert(pAnim);
		assert(pAnim->m_nGlobalAnimId>-1);
		if (pAnim->m_nAssetType==AIM_File)
		{
			GlobalAnimationHeaderAIM& rGAH = g_AnimationManager.m_arrGlobalAIM[pAnim->m_nGlobalAnimId];
			uint32 numPoses = rGAH.m_arrAimIKPosesAIM.size();
			if (numPoses==0)
				continue;
			if (rGAH.m_nExist==0)
				continue;

			SDirInfo	&rCurDirInfo = rDirIK.m_DirInfo[rDirIK.m_numActiveDirPoses];
			rCurDirInfo.m_numDirPoses		= 1;
			rCurDirInfo.m_fWeight				= rCurLayer[i].m_fTransitionWeight*t1;
			rCurDirInfo.m_fAnimTime			= 0;
			rCurDirInfo.m_nGlobalDirID0	= pAnim->m_nGlobalAnimId; 

			//	g_pIRenderer->Draw2dLabel( 1,g_YLine, 1.3f, fTextColor, false,"Dir in DirIK Layer: %d  weight: %f",nDirIKLayer,rCurLayer[i].m_fTransitionWeight);
			//	g_YLine+=10;
			rDirIK.m_numActiveDirPoses++;
			continue;
		}
		//	g_pIRenderer->Draw2dLabel( 1,g_YLine, 1.4f, fTextColor, false,"Normal Animation in Dir-IK   rDirIK.m_numActiveDirPoses: %d",rDirIK.m_numActiveDirPoses);	
		//	g_YLine+=16.0f;
	}

}

